package com.zhijian.medical.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.zhijian.medical.dao.local.AssessmentMapper;
import com.zhijian.medical.entity.UploadParam;
import com.zhijian.medical.entity.po.Assessment;
import com.zhijian.medical.entity.po.AssessmentDetail;
import com.zhijian.medical.entity.po.AssessmentStudy;
import com.zhijian.medical.entity.po.StudyClass;
import com.zhijian.medical.entity.vo.request.*;
import com.zhijian.medical.entity.vo.response.*;
import com.zhijian.medical.enums.AssessmentStatusEnum;
import com.zhijian.medical.holder.CurrentUserHolder;
import com.zhijian.medical.service.*;
import com.zhijian.medical.util.AssertUtil;
import com.zhijian.medical.util.Page;
import com.zhijian.medical.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 考核主表业务处理层
 *
 * @author HCG
 * @version: 1.0
 * @date 2023-01-17 16:40:22
 */
@Slf4j
@Service
public class AssessmentServiceImpl implements AssessmentService {

    @Autowired
    private AssessmentMapper mapper;

    @Autowired
    private AssessmentPaperService assessmentPaperService;

    @Autowired
    private AssessmentPaperQuestionService assessmentPaperQuestionService;

    @Autowired
    private AssessmentDscPaperPersonService assessmentDscPaperPersonService;

    @Autowired
    private AssessmentPaperPersonResultService assessmentPaperPersonResultService;

    @Autowired
    private AssessmentPaperPersonService assessmentPaperPersonService;

    @Autowired
    private AssessmentDetailService assessmentDetailService;

    @Autowired
    private AssessmentStudyService assessmentStudyService;

    @Autowired
    private ExamWarehouseService examWarehouseService;

    @Autowired
    private DigitalSliceCaseService digitalSliceCaseService;

    @Autowired
    private UploadParam uploadParam;

    @Autowired
    private StudyClassService studyClassService;

    @Override
    public Assessment selectById(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public AssessmentVo selectVoById(Long id) {
        AssessmentVo assessmentVo = mapper.selectVoById(id);
        if (Objects.isNull(assessmentVo)) {
            return null;
        }
        String doPersonIdsStr = assessmentVo.getDoPersonIdsStr();
        if (StringUtils.isNotBlank(doPersonIdsStr)) {
            assessmentVo.setDoPersonIds(Arrays.stream(doPersonIdsStr.split(",")).map(Long::valueOf).collect(Collectors.toList()));
        }
        String reviewerIdsStr = assessmentVo.getReviewerIdsStr();
        if (StringUtils.isNotBlank(reviewerIdsStr)) {
            assessmentVo.setReviewerIds(Arrays.stream(reviewerIdsStr.split(",")).map(Long::valueOf).collect(Collectors.toList()));
        }
        String digitalSliceCaseType = assessmentVo.getDigitalSliceCaseType();
        if (StringUtils.isNotBlank(digitalSliceCaseType)) {
            assessmentVo.setDigitalSliceCaseTypeList(Arrays.stream(digitalSliceCaseType.split(",")).collect(Collectors.toList()));
        }
        String groupIds = assessmentVo.getGroupIds();
        if (StringUtils.isNotBlank(groupIds)) {
            assessmentVo.setGroupIdList(Arrays.stream(groupIds.split(",")).map(Long::valueOf).collect(Collectors.toList()));
        }
        AssessmentDetailVo assessmentDetailVo = assessmentDetailService.selectByAssessmentId(id);
        if (Objects.nonNull(assessmentDetailVo)) {
            assessmentVo.setSingleSelectionNum(assessmentDetailVo.getSingleSelectionNum());
            assessmentVo.setSingleSelectionSingleScore(assessmentDetailVo.getSingleSelectionSingleScore());
            assessmentVo.setMultipleSelectionNum(assessmentDetailVo.getMultipleSelectionNum());
            assessmentVo.setMultipleSelectionSingleScore(assessmentDetailVo.getMultipleSelectionSingleScore());
            assessmentVo.setDscNum(assessmentDetailVo.getDscNum());
            assessmentVo.setDscSingleScore(assessmentDetailVo.getDscSingleScore());
        }
        assessmentVo.setId(id);
        //看看是否有关联学习模块，有的话把id组装进去
        List<AssessmentStudyVo> assessmentStudyVos = assessmentStudyService.selectList(AssessmentStudySearchVo.builder()
                .assessmentId(id)
                .build());
        if (CollectionUtil.isNotEmpty(assessmentStudyVos)) {
            assessmentVo.setStudyId(assessmentStudyVos.stream().map(AssessmentStudyVo::getStudyId).collect(Collectors.toList()));
        }
        return assessmentVo;
    }

    @Override
    public List<Assessment> selectByStatus(Byte status) {
        return mapper.selectByStatus(status);
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public void deleteById(Long id) {
        mapper.deleteByPrimaryKey(id);
        assessmentDscPaperPersonService.deleteByAssessmentId(id);
        assessmentPaperPersonResultService.deleteByAssessmentId(id);
        assessmentPaperPersonService.deleteByAssessmentId(id);
        assessmentPaperQuestionService.deleteByAssessmentId(id);
        assessmentPaperService.deleteByAssessmentId(id);
    }

    @Override
    public Long insert(Assessment assessment) {
        Date now = new Date();
        assessment.setCreateTime(now);
        assessment.setUpdateTime(now);
        return mapper.insert(assessment) > 0 ? assessment.getId() : 0L;
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public boolean save(AssessmentSaveOrUpdateVo assessmentSaveOrUpdateVo) {
        Assessment assessment = new Assessment();
        assessment.setName(assessmentSaveOrUpdateVo.getName());
        DateTime start = DateUtil.parseDateTime(assessmentSaveOrUpdateVo.getStartTime());
        DateTime end = DateUtil.parseDateTime(assessmentSaveOrUpdateVo.getEndTime());
        AssertUtil.check(start.compareTo(end) == 0 || start.after(end), "开始时间必须早于结束时间");
        Date now = new Date();
        AssertUtil.check(now.after(end), "结束时间不能早于现在");

        if (Objects.nonNull(assessmentSaveOrUpdateVo.getStudyClassId())) {
            StudyClass studyClass = studyClassService.selectById(assessmentSaveOrUpdateVo.getStudyClassId());
            AssertUtil.notNull(studyClass, "此学习班不存在或者已被删除");
            //如果传了学习班ID，就要验重
            Assessment assessmentVo = this.selectByStudyClassId(assessmentSaveOrUpdateVo.getStudyClassId());
            AssertUtil.check(Objects.nonNull(assessmentVo), "此学习班已经关联过考核，请重新选择");

            //直接取这个学习班的做卷人ID
            assessment.setDoPersonIds(studyClass.getDoPersonIds());
        } else {
            //考试人ids
            if (CollectionUtil.isNotEmpty(assessmentSaveOrUpdateVo.getDoPersonIds())) {
                assessment.setDoPersonIds(StrUtil.join(",", assessmentSaveOrUpdateVo.getDoPersonIds()));
            }
        }
        assessment.setStartTime(start);
        assessment.setEndTime(end);

        if (CollectionUtil.isNotEmpty(assessmentSaveOrUpdateVo.getReviewerIds())) {
            //阅卷人ids
            assessment.setReviewerIds(StrUtil.join(",", assessmentSaveOrUpdateVo.getReviewerIds()));
        }
//        //状态按照时间来
        assessment.setStatus(now.after(start) && now.before(end) ?
                AssessmentStatusEnum.RUNNING.getCode().byteValue() : AssessmentStatusEnum.UN_START.getCode().byteValue());
        assessment.setExamWarehouseId(assessmentSaveOrUpdateVo.getExamWarehouseId());

        String digitalSliceCaseType = null;
        if (CollectionUtil.isNotEmpty(assessmentSaveOrUpdateVo.getDigitalSliceCaseTypeList())) {
            digitalSliceCaseType = String.join(",", assessmentSaveOrUpdateVo.getDigitalSliceCaseTypeList());
        }
        assessment.setDigitalSliceCaseType(digitalSliceCaseType);
        if (CollectionUtil.isNotEmpty(assessmentSaveOrUpdateVo.getGroupIdList())) {
            assessment.setGroupIds(StrUtil.join(",", assessmentSaveOrUpdateVo.getGroupIdList()));
        }
        //合格线
        assessment.setAcceptanceLine(assessmentSaveOrUpdateVo.getAcceptanceLine());
        assessment.setCreateUserId(CurrentUserHolder.getUser().getId());
        assessment.setCreateUserName(CurrentUserHolder.getUser().getName());
        //用户类型
        assessment.setUserType(assessmentSaveOrUpdateVo.getUserType());
        //学习班ID
        assessment.setStudyClassId(assessmentSaveOrUpdateVo.getStudyClassId());
        //先保存，获取考核id
        Long assessmentId = this.insert(assessment);
//        //生成个二维码 modify 2023-12-07 二维码挪到学习班里了
//        String qrByAssessmentId = this.createQrByAssessmentId(assessmentId);
//        this.updateByPrimaryKeySelective(Assessment.builder()
//                .id(assessmentId)
//                .qrFilePath(qrByAssessmentId)
//                .build());
        //保存与学习模块的关系表
        if (CollectionUtil.isNotEmpty(assessmentSaveOrUpdateVo.getStudyId())) {
            //批量保存
            assessmentStudyService.insertBatch(assessmentSaveOrUpdateVo.getStudyId().stream().map(studyId -> {
                AssessmentStudy assessmentStudy = new AssessmentStudy();
                assessmentStudy.setStudyId(studyId);
                assessmentStudy.setAssessmentId(assessmentId);
                assessmentStudy.setCreateTime(now);
                assessmentStudy.setUpdateTime(now);
                return assessmentStudy;
            }).collect(Collectors.toList()));
        }
        //题库，生成试卷
        AssessmentStartVo assessmentStartVo = new AssessmentStartVo();
        BeanUtils.copyProperties(assessmentSaveOrUpdateVo, assessmentStartVo);
        assessmentStartVo.setAssessmentId(assessmentId);
        assessmentStartVo.setWarehouseId(assessmentSaveOrUpdateVo.getExamWarehouseId());
        assessmentStartVo.setUserId(CurrentUserHolder.getUser().getId());
        assessmentStartVo.setDigitalSliceCaseType(digitalSliceCaseType);


        if (Objects.nonNull(assessmentSaveOrUpdateVo.getExamWarehouseId())) {
            ExamWarehouseVo examWarehouse = examWarehouseService.selectVoById(assessmentStartVo.getWarehouseId());
            AssertUtil.notNull(examWarehouse, "此题库不存在或者已被删除");
            AssertUtil.check(Objects.isNull(assessmentStartVo.getSingleSelectionNum()) || assessmentStartVo.getSingleSelectionNum() < 1, "单选题数目不能为空且须大于0");
            AssertUtil.check(Objects.isNull(assessmentStartVo.getSingleSelectionSingleScore()) || assessmentStartVo.getSingleSelectionSingleScore() < 1, "单选题分数不能为空且须大于0");
            AssertUtil.check(assessmentStartVo.getSingleSelectionNum() > examWarehouse.getQuestionNum(), String.format("此题库问题数目小于%s，无法通过", assessmentStartVo.getSingleSelectionNum()));

        }

        if (StringUtils.isNotBlank(digitalSliceCaseType)) {
            //如果有切片类型，则在这些类型中的病例中随机抽取病例
            AssertUtil.check(Objects.isNull(assessmentStartVo.getDscNum()) || assessmentStartVo.getDscNum() < 1, "病例题数目不能为空且须大于0");
            AssertUtil.check(Objects.isNull(assessmentStartVo.getDscSingleScore()) || assessmentStartVo.getDscSingleScore() < 1, "病例题分数不能为空且须大于0");

            List<DigitalSliceCaseVo> digitalSliceCaseVos = digitalSliceCaseService.selectListOnly(DigitalSliceCaseSearchVo.builder()
                    .typeList(Arrays.asList(digitalSliceCaseType.split(",")))
                    .userType(assessmentSaveOrUpdateVo.getUserType())
                    .build());
            AssertUtil.check(assessmentStartVo.getDscNum() > digitalSliceCaseVos.size(), String.format("系统中存在的病例数目小于%s，无法通过", assessmentStartVo.getDscNum()));

        }

        if (CollectionUtil.isNotEmpty(assessmentSaveOrUpdateVo.getGroupIdList())) {
            AssertUtil.check(Objects.isNull(assessmentStartVo.getDscNum()) || assessmentStartVo.getDscNum() < 1, "病例题数目不能为空且须大于0");
            AssertUtil.check(Objects.isNull(assessmentStartVo.getDscSingleScore()) || assessmentStartVo.getDscSingleScore() < 1, "病例题分数不能为空且须大于0");
            //专项培训人员的
            //病例分组ID数组
            List<DigitalSliceCaseVo> digitalSliceCaseVos = digitalSliceCaseService.selectListOnly(DigitalSliceCaseSearchVo.builder()
                    .groupIdList(assessmentSaveOrUpdateVo.getGroupIdList())
                    .userType(assessmentSaveOrUpdateVo.getUserType())
                    .build());
            AssertUtil.check(assessmentStartVo.getDscNum() > digitalSliceCaseVos.size(), String.format("系统中存在的病例数目小于%s，无法通过", assessmentStartVo.getDscNum()));
        }

        AssessmentDetail assessmentDetail = new AssessmentDetail();
        BeanUtils.copyProperties(assessmentStartVo, assessmentDetail);
        assessmentDetail.setAssessmentId(assessmentStartVo.getAssessmentId());

        assessmentDetailService.insert(assessmentDetail);
//        assessmentPaperService.generate(assessmentStartVo);
        return assessmentId != 0;
    }

    @Override
    public boolean update(Assessment assessment) {
        Date now = new Date();
        assessment.setUpdateTime(now);
        return mapper.updateByPrimaryKey(assessment) != 0;
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public boolean modify(AssessmentSaveOrUpdateVo assessmentSaveOrUpdateVo) {
        Long assessmentId = assessmentSaveOrUpdateVo.getId();
        Assessment assessment = this.selectById(assessmentId);
        AssertUtil.notNull(assessment, "此次考核不存在或者已被删除");
//        AssertUtil.check(assessment.getStatus() != AssessmentStatusEnum.UN_START.getCode().byteValue(), "只能修改未开始的考核");
        Date now = new Date();

        assessment.setName(assessmentSaveOrUpdateVo.getName());
        DateTime start = DateUtil.parseDateTime(assessmentSaveOrUpdateVo.getStartTime());
        DateTime end = DateUtil.parseDateTime(assessmentSaveOrUpdateVo.getEndTime());
        AssertUtil.check(now.after(start), "只能修改未开始的考核");
        AssertUtil.check(start.compareTo(end) == 0 || start.after(end), "开始时间必须早于结束时间");

        AssertUtil.check(now.after(end), "结束时间不能早于现在");
        assessment.setStartTime(start);
        assessment.setEndTime(end);
        if (Objects.nonNull(assessmentSaveOrUpdateVo.getStudyClassId())) {
            StudyClass studyClass = studyClassService.selectById(assessmentSaveOrUpdateVo.getStudyClassId());
            AssertUtil.notNull(studyClass, "此学习班不存在或者已被删除");
            //如果传了学习班ID，就要验重
            Assessment assessmentVo = this.selectByStudyClassId(assessmentSaveOrUpdateVo.getStudyClassId());
            AssertUtil.check(Objects.nonNull(assessmentVo) && !Objects.equals(assessmentVo.getId(), assessmentId), "此学习班已经关联过考核，请重新选择");

            //直接取这个学习班的做卷人ID
            assessment.setDoPersonIds(studyClass.getDoPersonIds());
        } else {
            //考试人ids
            if (CollectionUtil.isNotEmpty(assessmentSaveOrUpdateVo.getDoPersonIds())) {
                assessment.setDoPersonIds(StrUtil.join(",", assessmentSaveOrUpdateVo.getDoPersonIds()));
            }
        }
        //阅卷人ids
        assessment.setReviewerIds(StrUtil.join(",", assessmentSaveOrUpdateVo.getReviewerIds()));
        //状态按照时间来
        assessment.setStatus(now.after(start) && now.before(end) ?
                AssessmentStatusEnum.RUNNING.getCode().byteValue() : AssessmentStatusEnum.UN_START.getCode().byteValue());
        assessment.setExamWarehouseId(assessmentSaveOrUpdateVo.getExamWarehouseId());
        String digitalSliceCaseType = null;
        if (CollectionUtil.isNotEmpty(assessmentSaveOrUpdateVo.getDigitalSliceCaseTypeList())) {
            digitalSliceCaseType = String.join(",", assessmentSaveOrUpdateVo.getDigitalSliceCaseTypeList());
        }
        assessment.setDigitalSliceCaseType(digitalSliceCaseType);
        //合格线
        assessment.setAcceptanceLine(assessmentSaveOrUpdateVo.getAcceptanceLine());
        this.update(assessment);
        //先删除之前生成的试卷表
        assessmentPaperService.deleteByAssessmentId(assessmentId);
        assessmentPaperQuestionService.deleteByAssessmentId(assessmentId);
        assessmentDetailService.deleteByAssessmentId(assessmentId);
        assessmentStudyService.deleteByAssessmentId(assessmentId);
        //先保存，获取考核id
        //保存与学习模块的关系表
        if (CollectionUtil.isNotEmpty(assessmentSaveOrUpdateVo.getStudyId())) {
            //批量保存
            assessmentStudyService.insertBatch(assessmentSaveOrUpdateVo.getStudyId().stream().map(studyId -> {
                AssessmentStudy assessmentStudy = new AssessmentStudy();
                assessmentStudy.setStudyId(studyId);
                assessmentStudy.setAssessmentId(assessmentId);
                assessmentStudy.setCreateTime(now);
                assessmentStudy.setUpdateTime(now);
                return assessmentStudy;
            }).collect(Collectors.toList()));
        }
        //题库，生成试卷
        AssessmentStartVo assessmentStartVo = new AssessmentStartVo();
        assessmentStartVo.setAssessmentId(assessmentId);
        assessmentStartVo.setWarehouseId(assessmentSaveOrUpdateVo.getExamWarehouseId());
        assessmentStartVo.setUserId(CurrentUserHolder.getUser().getId());
        assessmentStartVo.setDigitalSliceCaseType(digitalSliceCaseType);
//        assessmentPaperService.generate(assessmentStartVo);
        return true;
    }

    @Override
    public boolean updateByPrimaryKeySelective(Assessment record) {
        Date now = new Date();
        record.setUpdateTime(now);
        return mapper.updateByPrimaryKeySelective(record) != 0;
    }

    @Override
    public Integer count(AssessmentSearchVo assessmentSearchVo) {
        return mapper.count(assessmentSearchVo);
    }

    @Override
    public List<AssessmentVo> selectList(AssessmentSearchVo assessmentSearchVo) {
        List<AssessmentVo> assessmentVos = mapper.selectList(assessmentSearchVo);
        if (CollectionUtil.isEmpty(assessmentVos)) {
            return Collections.emptyList();
        }
        assessmentVos.forEach(assessmentVo -> {
            //查询出这个个考核的关联学习资料名称
            String studyNames = assessmentStudyService.selectStudyNamesByAssessmentId(assessmentVo.getId());
            assessmentVo.setRelationStudyNames(studyNames);
        });
        return assessmentVos;
    }

    @Override
    public Page<AssessmentVo> selectPage(AssessmentSearchVo assessmentSearchVo) {
        //先直接查总数
        int count = count(assessmentSearchVo);
        //分页
        Page<AssessmentVo> page = new Page<>(true, count, assessmentSearchVo.getPageNum(), assessmentSearchVo.getPageSize());
        assessmentSearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<AssessmentVo> responseVos = this.selectList(assessmentSearchVo);
        page.setData(responseVos);
        return page;
    }

    @Override
    public boolean insertBatch(List<Assessment> entities) {
        return CollectionUtil.isNotEmpty(entities) && mapper.insertBatch(entities) > 0;
    }

    @Override
    public Assessment selectByStudyClassId(Long studyClassId) {
        return mapper.selectByStudyClassId(studyClassId);
    }

    /**
     * 根据考核ID生成二维码
     *
     * @param assessmentId
     * @return
     */
    private String createQrByAssessmentId(Long assessmentId) {
        //文件储存路径
        String storePath = uploadParam.getStorePath();
        // 生成指定url对应的二维码到文件，宽和高都是300像素
        String realPath = String.format("%s%s.jpg", storePath, assessmentId);
        //内容
        String content = String.format("https://njglyy.zhijianiot.com/register?assessmentId=%s", assessmentId);
        QrCodeUtil.generate(content, 300, 300, FileUtil.file(realPath));
        return String.format("%s%s", uploadParam.getUrlPath(), String.format("%s.jpg", assessmentId));
    }

}